#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <setjmp.h>
#include <cmocka.h>

#include "../src/stream.h"

static void test_stream_new(void **state)
{
    stream_t *s = NULL;
    s = stream_new();
    assert_non_null(s);
}

static void test_stream_delete(void **state)
{
    stream_t *s = NULL;
    s = stream_new();
    stream_delete(s);
    stream_delete(NULL);
}

static int setup(void **state)
{
    stream_t *s = stream_new();
    *state = s;
    return 0;
}

static int teardown(void **state)
{
    stream_t *s = *state;
    stream_delete(s);
    return 0;
}

static void test_stream_write(void **state)
{
    stream_t *s = *state;
    int i = 0, bits = 16;
    uint8_t *buff = malloc(2 << bits);
    int32_t len = 0;

    assert_non_null(buff);
    for (i = 0; i < bits; i++) {
        memset(buff, i, 2 << i);
        len = stream_write(s, buff, 2 << i);
        assert_int_equal(2 << i, len);
        print_message("%-2d write %-10d[result:%-10d]\n", i, 2 << i, len);
    }
    free(buff);
}

static void test_stream_read(void **state)
{
    stream_t *s = *state;
    int i = 0, bits = 16;
    uint8_t *wbuff = malloc(2 << bits);
    uint8_t *rbuff = malloc(2 << bits);
    int32_t len = 0;

    for (i = 0; i < bits; i++) {
        memset(wbuff, i, 2 << i);
        len = stream_write(s, wbuff, 2 << i);
        len = stream_read(s, rbuff, 2 << i);
        print_message("%-2d read %-10d[result:%-10d]\n", i, 2 << i, len);
        assert_memory_equal(wbuff, rbuff, 2 << i);
    }

    len = stream_write(s, wbuff, 2 << i);
    len = stream_read(s, rbuff, (2 << i)+1);
    print_message("%-2d read %-10d[result:%-10d]\n", i, 2 << i, len);

    free(wbuff);
    free(rbuff);
}

static void test_stream_get_length(void **state)
{

}

int main(int argc, char **argv)
{
    const struct CMUnitTest tests[] = {
        cmocka_unit_test(test_stream_new),
        cmocka_unit_test(test_stream_delete),
        cmocka_unit_test_setup_teardown(test_stream_write, setup, teardown),
        cmocka_unit_test_setup_teardown(test_stream_read, setup, teardown),
        cmocka_unit_test_setup_teardown(test_stream_get_length, setup, teardown)
    };
    cmocka_run_group_tests(tests, NULL, NULL);
    return 0;
}
